package com.wbp.cms.web.controller.admin;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.ReaderException;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.decoder.Version;
import com.wbp.cms.client.common.domain.QRCodeDO;
import com.wbp.cms.client.common.query.QRCodeQuery;
import com.wbp.cms.client.common.service.QRCodeService;
import com.wbp.cms.client.common.vo.ZXingOptionalVO;
import com.wbp.cms.client.constant.CommonConstant;
import com.wbp.cms.client.result.Result;
import com.wbp.cms.client.user.domain.UserDO;
import com.wbp.cms.client.util.JsonUtils;
import com.wbp.cms.core.service.image.ImageUploadYunManager;
import com.wbp.cms.core.util.CommonProperties;
import com.wbp.cms.core.util.QRCodeUtils;
import com.wbp.cms.web.controller.BaseController;


/**
 * @Description:
 * @Department:
 * @author andy.lhc
 * @date 2016年3月16日 下午9:05:50
 */
@Controller("qRCodeMgrController")
@RequestMapping("/qrcodemgr")
public class QRCodeMgrController extends BaseController {

  private static final Logger logger =Logger.getLogger(QRCodeMgrController.class) ;
  
  @Resource
  private QRCodeService qRCodeService;

  private static final int BLACK = 0xff000000;
  private static final int WHITE = 0xFFFFFFFF;

  @Resource(name="imageUploadYunManager")
  private ImageUploadYunManager  imageUploadYunManager ;
  
  /**
   * 进入页面时的方法
   * 
   * @return
   */
  @RequestMapping("/tolist")
  public ModelAndView toList() {
    ModelAndView mv = new ModelAndView();
    mv.setViewName("admin/qrcode/qrcodeList");
    return mv;
  }

  @RequestMapping(value = "/query", produces = "application/json;charset=UTF-8")
  @ResponseBody
  public String doQuery(HttpServletRequest request, @RequestParam(value = "userName",
      required = false, defaultValue = "") String userName, @RequestParam(value = "mobileNumber",
      required = false, defaultValue = "") String mobileNumber, @RequestParam(value = "code",
      required = false, defaultValue = "") String code, @RequestParam(value = "start",
      required = false, defaultValue = "1") int start, @RequestParam(value = "length",
      required = false, defaultValue = "50") int pageSize) {

    Map<String, String> maps = this.getParameters(request);

    QRCodeQuery query = new QRCodeQuery();
    // /userQuery.setPageNo(pageNo);
    query.setStart(start);
    query.setPageSize(pageSize);
    query.setUserName(userName);
    query.setMobileNumber(mobileNumber);
    query.setCode(code);

    Result<List<QRCodeDO>> result = qRCodeService.query(query);
    return new Gson().toJson(getDataTableMapData(result, maps.get(DT_KEY_DRAW)));
  }

  /**
   * 生成二维码，保存到云服务器中去，返回url
   * 
   * @param request
   * @return
   */
  @RequestMapping(value="/createqrcode", produces = "application/json;charset=UTF-8")
  @ResponseBody
  public String doCreateQRCode(HttpServletRequest request) {

   // String baseUrl = CommonProperties.getInstance().getProperties(CommonConstant.baseQRUrl);
    FileOutputStream fos = null ;
    UserDO userDO = this.getRequestObject(request, UserDO.class);
    
    if(userDO ==null || userDO.getId() ==null || userDO.getId()<=0)
       return new Gson().toJson(Result.buildError("userId不能为空,请刷新界面"));
    if(StringUtils.isEmpty(userDO.getUserName()))
       return new Gson().toJson(Result.buildError("userName不能为空,请刷新界面"));
    if(StringUtils.isEmpty(userDO.getMobileNumber()))
      return new Gson().toJson(Result.buildError("mobileNumber不能为空,请刷新界面"));
    
    // 判断 ，先把之前上传到oss文件中的二维码存储地址删除掉
    
    String fileName = userDO.getId()+"_"+userDO.getUserName()+"_"+System.currentTimeMillis()+".png" ;
    Map<String,String> maps = Maps.newTreeMap() ;
    maps.put("userId", userDO.getId().toString()) ;
    maps.put("userName",userDO.getUserName()) ;
    maps.put("mobileNumber",userDO.getMobileNumber()) ;
    //String filePath = encode(fileName,maps,userDO.getWidth(),userDO.getHeight()) ;
 
   // if(filePath == null || filePath.equals("")) 
  //    return new Gson().toJson(Result.buildError("生成二维码失败")); 
   /* 
    try {
            File  file =   new File(filePath) ;
            Map<String,String> map =  imageUploadYunManager.getUploadYunService().uploadFile(file, fileName) ;
            if(file.exists())
               file.delete(); //上传完删除文件 
            return JsonUtils.toJson(Result.buildSuccess(map.get("ossurl"))) ;
        } catch (IOException e) {
          logger.error("doGetImageUploadUrl exception:",e);
          return JsonUtils.toJson(Result.buildError("上传出错")) ;
         }

   */
         File  file =null  ;
        try {
                file = new File("c:\\"+fileName ) ;
                fos  = new FileOutputStream(file) ;
                ZXingOptionalVO optionalVO = new ZXingOptionalVO();
                optionalVO.setEcLevel(ErrorCorrectionLevel.Q);
                optionalVO.setVersion(Version.getVersionForNumber(15));
                optionalVO.setEcLevel(ErrorCorrectionLevel.H);
                optionalVO.setMargin(1);
                 // 最好在 100*100个像素以内，60k大小以内 png格式，如果太长的，decode会有问题，解析不出来 
                URL  logoUrl = new URL(userDO.getImage()) ;
                BufferedImage bi =  ImageIO.read(logoUrl) ;  
                String baseQRUrl = CommonProperties.getInstance().getProperties(CommonConstant.baseQRUrl) ;
                String params = baseQRUrl + getUrl(maps) ;
               // System.out.println("params : "+params);
               
                 QRCodeUtils.encodeQrcode(params, bi, 250, 250, optionalVO, fos ); 
                 if(!file.exists())
                    return new Gson().toJson(Result.buildError("生成二维码失败")); 
               // System.out.println( QRCodeUtils.decode(file));
                 
                 Map<String,String> map =  imageUploadYunManager.getUploadYunService().uploadFile(file, fileName) ;  // 上传oss中 
                String ossurl =  map.get("ossurl") ;
               // System.out.println("ossurl : "+ossurl);
                if(StringUtils.isBlank(ossurl))
                   return new Gson().toJson(Result.buildError("上传二维码失败")); 
                
                return JsonUtils.toJson(Result.buildSuccess(ossurl)) ;
          } catch (Exception e) {
            logger.error("exception1:",e);
            return JsonUtils.toJson(Result.buildError("生成二维码出错,请检查!")) ;
          }finally{
            
            if(file!=null && file.exists())
                  file.delete(); //上传完删除文件 
              try {
                if(fos !=null)
                   fos.close();
              } catch (IOException e) {
                 logger.error("exception2:",e);
              } 
          }    
   // return new Gson().toJson(Result.buildError("上传二维码失败"));
  }


  /**
   * 解码二维码中的信息
   * @param request
   * @return
   */
  @RequestMapping(value="/dodecodeqrcoce", produces = "application/json;charset=UTF-8")
  @ResponseBody
  public String doDecodeQRCode(HttpServletRequest request,
                              @RequestParam(value="qrcodeurl",defaultValue="",required=true) String qrcodeurl) {
       if(qrcodeurl ==null || qrcodeurl.equals(""))
         return JsonUtils.toJson(Result.buildError("qrcodeurl为空")) ;
       //  this.decode(fileName)
       // 先用oss下载到c盘中，解码后删除临时文件 
       
       
       
       return "";
  }

  /**
   * 保存生成的用户二维码记录
   * 
   * @param request
   * @return
   */
  @RequestMapping(value="/doaddqrcoce", produces = "application/json;charset=UTF-8")
  @ResponseBody
  public String doAddQRCode(HttpServletRequest request) {
    QRCodeDO qrCodeDO = this.getRequestObject(request, QRCodeDO.class);

    if (qrCodeDO == null)
      return new Gson().toJson(Result.buildError("参数不能为空"));
    if (qrCodeDO.getId() == null || qrCodeDO.getId() <= 0)
      return new Gson().toJson(Result.buildError("qrCode.id不能为空"));
    if (StringUtils.isEmpty(qrCodeDO.getUserName()))
      return new Gson().toJson(Result.buildError("UserName不能为空"));
    if (StringUtils.isEmpty(qrCodeDO.getMobileNumber()))
      return new Gson().toJson(Result.buildError("MobileNumber不能为空"));
    if (StringUtils.isEmpty(qrCodeDO.getMainWxUrl()))
      return new Gson().toJson(Result.buildError("MainWxUrl不能为空"));

    Result<Long> r = this.qRCodeService.addQRCode(qrCodeDO);
    if (r.isFailed())
      return new Gson().toJson(Result.buildError(r.getErrMsg()));

    return new Gson().toJson(Result.buildSuccess(""));
  }

  /**
   * 下载二维码图片
   * 
   * @param qrcodeId
   * @return
   */
  @RequestMapping("/downqrcoce")
  @ResponseBody
  public String downQRCode(
      @RequestParam(value = "qrcodeId", required = true, defaultValue = "0") Long qrcodeId) {


    return "";
  }

  /**
   * 删除
   * 
   * @return
   */
  @RequestMapping(value = "/todelete", produces = "application/json;charset=UTF-8")
  @ResponseBody
  public String toDelete(@RequestParam(value = "id", required = true, defaultValue = "0") Long id) {
    if (id <= 0) {
      return JsonUtils.toJson(Result.buildError("id:" + id + ",应>0"));
    }

    boolean b = this.qRCodeService.deleteQRCode(id);
    if (!b)
      return JsonUtils.toJson(Result.buildError("id:" + id + "删除二维码出错,请联系管理员"));

    return JsonUtils.toJson(Result.buildSuccess(b));
  }


 
   /**
   * 在编码时需要将com.google.zxing.qrcode.encoder.Encoder.java中的
   *  static final String DEFAULT_BYTE_MODE_ENCODING = "ISO8859-1";
   *  修改为UTF-8，否则中文编译后解析不了
   *  如果要用中文，先java类编码，再解码
   */
  private  String encode(String fileName,Map<String,String> maps,int width,int height) {
    try {
          String baseQRUrl = CommonProperties.getInstance().getProperties(CommonConstant.baseQRUrl) ;
          String str = baseQRUrl+getUrl(maps) ; // 二维码内容
          String path = "C:\\"+fileName;
          BitMatrix m;
          Map<EncodeHintType,Object> hints = Maps.newHashMap();
          hints.put(EncodeHintType.MARGIN, 0) ;  // 控制生成的Bit图和图片大小的边柜 0表示全部填满 
          m = new QRCodeWriter().encode(str, BarcodeFormat.QR_CODE, width, height,hints);  // new MultiFormatWriter()
          File file = new File(path);
         // FileOutputStream fos = new FileOutputStream(file) ;
          writeToFile(m, "png", file);
          //MatrixToImageWriter.writeToStream(m, "png", fos );
          return path ;
      } catch (Exception e) {
        logger.error("exception encode: ",e);
        return null ;
      }finally{
         
      }
  }
  
  /**
   * 
   * @param maps
   * @return
   */
  private String  getUrl(Map<String,String> maps){
    StringBuilder sb =new StringBuilder();
    if(maps == null || maps.isEmpty() )
      return sb.toString() ;
    for( Entry<String, String>  entry :  maps.entrySet()){
         sb.append(entry.getKey()+"="+entry.getValue()) ;
         sb.append("&");
    }
    return sb.toString() ;
  }
  
  private Map<String,String> getParametersFromUrl(String url){
    Map<String,String> maps =Maps.newTreeMap() ;
    if(StringUtils.isEmpty(url))
       return maps ;
    maps.put("url", url) ;
    int len = url.indexOf("?")  ;
    if(len <=0)
      return maps ;
    String url2 = url.substring(len+1) ;
    String[]  strArray = url2.split("&") ;
    for(String str: strArray){
        String[] array = str.split("=") ;
        maps.put(array[0], array[1]) ;
    }
    
    return maps ;
  }
  
  public static void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
    BufferedImage image = toBufferedImage(matrix);
    ImageIO.write(image, format, file);
  }

  public static BufferedImage toBufferedImage(BitMatrix matrix) {
    int width = matrix.getWidth();
    int height = matrix.getHeight();
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    for (int x = 0; x < width; x++) {
      for (int y = 0; y < height; y++) {
        image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
      }
    }
    return image;
  }
  
  
  /**
   * 解码
   */
  public Map<String,String> decode(String fileName) {
    try {
      // Reader reader = new MultiFormatReader();
      String imgPath = "C:\\"+fileName ;
      File file = new File(imgPath); 
      BufferedImage image;
      try {
        image = ImageIO.read(file);
        if (image == null) {
          System.out.println("Could not decode image");
        }
        LuminanceSource source = new BufferedImageLuminanceSource(image);
        BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
        com.google.zxing.Result result;
        Map<DecodeHintType,String> hints = new HashMap<DecodeHintType,String>();
        hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
        // 解码设置编码方式为：utf-8，
        result = new MultiFormatReader().decode(bitmap, hints);
        String resultStr = result.getText();
        logger.error("解析后内容：" + resultStr);
        return  getParametersFromUrl(resultStr) ;
      } catch (IOException ioe) {
        logger.error("exception 1: ",ioe);
      } catch (ReaderException re) {
        logger.error("exception 2: ",re);
      }
    } catch (Exception ex) {
      logger.error("exception 3: ",ex);
    }
    return null ;
  }

  public static void main(String[] args) {
    QRCodeMgrController qcc = new QRCodeMgrController();
    Map<String,String> map = Maps.newTreeMap() ;
    map.put("username", "lihc") ;
    map.put("userid", "22") ;
    long time= System.currentTimeMillis() ;
    String fileName = "test"+time+".png" ;
    qcc.encode(fileName,map,430,430);
     System.out.println( qcc.decode(fileName) );
  }
  
}
